package com.jse.json;

import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.Date;

import com.jse.Lang;
import com.jse.Times;

public class Jwt {

	private String key;
//	private String signer;//算法
	private JsonObject payload;
	private JsonObject header;
	private Charset charset;
	private String[] tokens;
	public Jwt() {
		header=new JsonObject();
		payload=new JsonObject(true);//date转time
		charset=StandardCharsets.UTF_8;
	}
	public Jwt(final String token) {
		charset=StandardCharsets.UTF_8;
		parse(token);
	}
	
	public static Jwt of() {return new Jwt();}
	public static Jwt of(String token) {return new Jwt(token);}
	
	public Jwt parse(final String token) throws IllegalArgumentException {
		this.tokens = token.split("\\.");
		this.header=Json.parse(new String(Base64.getDecoder().decode(tokens[0].getBytes(charset)),charset),JsonObject.class);
		this.payload=Json.parse(new String(Base64.getDecoder().decode(tokens[1].getBytes(charset)),charset),JsonObject.class);
		return this;
	}
	
	public Jwt setKey(String key) {
		this.key=key;
		return this;
	}
	
	public Jwt setPayload(String name,Object value) {
		payload.set(name, value);
		return this;
	}
	/** 过期时间 必须大于签发时间 */
	public Jwt setExpiresAt(Date d) {
		return setPayload("exp",d);
	}
	/** 签发时间 */
	public Jwt setIssuedAt(Date d) {
		return setPayload("iat",d);
	}
	public Jwt setJwtID(String jid) {
		return setPayload("jti",jid);
	}
	/**
	 * 生效时间
	 * @param d 不可用时间点界限，在这个时间点之前，jwt不可用
	 * @return
	 */
	public Jwt setNotBefore(Date d) {
		return setPayload("nbf",d);
	}
	
	public String sign() throws Exception {
		// 检查tye信息
		final String type = (String) this.header.get("typ");
		if (type==null||type.isBlank()) {
			this.header.set("typ","JWT");
		}

		// 检查头信息中是否有算法信息
		final String algorithm = (String) this.header.get("alg");
		if (algorithm==null||algorithm.isEmpty()) {
			this.header.set("alg","HS256");
		}

		final String headerBase64 = Base64.getUrlEncoder().withoutPadding().encodeToString(this.header.toString().getBytes(StandardCharsets.UTF_8));
		final String payloadBase64 = Base64.getUrlEncoder().withoutPadding().encodeToString(this.payload.toString().getBytes(StandardCharsets.UTF_8));
		var sign=sign(headerBase64,payloadBase64);
		return String.format("%s.%s.%s", headerBase64, payloadBase64,sign);
	}
	private String sign(String headerBase64,String payloadBase64) {
		try {
			var sign0=Lang.hmacSHA256(key,String.format("%s.%s", headerBase64, payloadBase64));
			return Base64.getUrlEncoder().withoutPadding().encodeToString(sign0);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
	
	/** 验证签名*/
	public boolean verify() {
		var t3=sign(tokens[0],tokens[1]);
		return t3.equals(tokens[2]);
	}
	/*Token是否正确
	生效时间不能晚于当前时间
	失效时间不能早于当前时间
	签发时间不能晚于当前时间*/
	public boolean validate() {
		if (!verify()) {
			return false;
		}
		long now=System.currentTimeMillis();
		// 检查生效时间（生效时间不能晚于当前时间）
		final Long notBefore = payload.getLong("nbf",now);
		if(notBefore<now) {
			System.out.println("生效时间晚于当前时间");
			return false;
		}
		// 检查失效时间（失效时间不能早于当前时间）
		final Long expiresAt = payload.getLong("exp",now);
		if(expiresAt<now) {
			System.out.println("失效时间早于当前时间");
			return false;
		}
		// 检查签发时间（签发时间不能晚于当前时间）
		final Long issueAt = payload.getLong("iat",now);
		if(issueAt<now) {
			System.out.println("签发时间晚于当前时间");
			return false;
		}
		return true;
	}
	
	public static void main(String[] args) throws Exception {
		final Jwt jwt = Jwt.of()
		.setPayload("sub", "1234567890")
		.setPayload("name", "looly")
		.setPayload("admin", true)
		.setExpiresAt(Times.parse("2023-10-27"))
		.setKey("1234567890");
//		String s="eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9." +
//				"eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6Imxvb2x5IiwiYWRtaW4iOnRydWUsImV4cCI6MTY0MDk2NjQwMH0." +
//				"bXlSnqVeJXWqUIt7HyEhgKNVlIPjkumHlAwFY-5YCtk";
//		System.out.println(s);
		var s1=jwt.sign();
		System.out.println(s1);
//		Jwt.of(s1).setKey("1234567890").verify();//基础签名验证
		System.out.println(Jwt.of(s1).setKey("1234567890").validate());//包含时间的验证
		//1640995200000
		//1640966400000
	}
	
}
